package com.pz.cloud.framework.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.pz.cloud.framework.base.constants.WorkflowContants;
import com.pz.cloud.framework.base.expection.CustomRuntimeException;
import com.pz.cloud.framework.base.model.BasePage;
import com.pz.cloud.framework.base.model.WorkflowEntity;
import com.pz.cloud.framework.base.threadLocal.ThreadLocalContext;
import com.pz.cloud.framework.business.workflow.entity.*;
import com.pz.cloud.framework.business.workflow.enums.WorkflowEnum;
import com.pz.cloud.framework.business.workflow.model.*;
import com.pz.cloud.framework.business.workflow.service.*;
import com.pz.cloud.framework.util.BizUtil;
import com.pz.cloud.framework.workflow.exception.WorkflowTaskException;
import com.pz.cloud.framework.workflow.mapper.ProcessTaskMapper;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.TreeNode;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TreeNodeUtil;
import org.jeecg.common.util.UUIDUtils;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.entity.SysUserDepart;
import org.jeecg.modules.system.model.SysUserSysDepartModel;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysUserDepartService;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

import static java.util.stream.Collectors.toList;


/**
 * 工作流服务
 *
 * @author mazezhan
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class WorkflowServiceImpl implements IWorkflowService {
    private static final List<String> HIGH_LIGHTED_FLOWS = new ArrayList(0);

    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private IProcessInfoService processInfoService;
    @Autowired
    private ProcessTaskMapper processTaskMapper;
    @Autowired
    private IWaitDoneService waitDoneService;
    @Autowired
    private ITaskNodeAttrService taskNodeAttrService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysDepartService sysDepartService;
    @Autowired
    private ISysUserDepartService sysUserDepartService;
    @Autowired
    private ITaskNodeFieldService taskNodeFieldService;
    @Autowired
    private IWaitDoneUserService waitDoneUserService;
    @Autowired
    private IWorkflowTaskService workflowTaskService;

    /**
     * 此方法在并行网关下有问题，不使用
     */
    @Deprecated
    public void revoke(String taskId) {
        WaitDone waitDone = waitDoneService.getById(taskId);
        if(waitDone==null){
            throw new CustomRuntimeException("该任务不存在，无法撤回");
        }
        boolean processEnd = isProcessEnd(waitDone.getProcessInstanceId());
        if(processEnd){
            throw new CustomRuntimeException("流程未启动或已执行完成，无法撤回");
        }
        HistoricTaskInstance historicTaskInstance = processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskAssignee(BizUtil.getUserId()).taskId(taskId).singleResult();
        if(historicTaskInstance==null){
            throw new CustomRuntimeException("非您任务，无法撤回！");
        }
        UserTask userTask = (UserTask) getFlowElement(historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getTaskDefinitionKey());
        if(userTask.hasMultiInstanceLoopCharacteristics()){
            throw new CustomRuntimeException("会签任务不能撤回！");
        }
        /**
         * 判断下一步任务是否已经完成
         */
        List<WaitDone> waitDones = waitDoneService.findByParentId(taskId);
        if(CollectionUtils.isEmpty(waitDones)){
            throw new CustomRuntimeException("该任务不能撤回！");
        }
        for (WaitDone done : waitDones) {
            if(done.getStatus()==1){
                throw new CustomRuntimeException("该任务不能撤回！");
            }
        }

        //当前任务
//        List<Task> curTasks = processEngine.getTaskService().createTaskQuery().processInstanceId(waitDone.getProcessInstanceId()).list();
        List<Task> curTasks = new ArrayList<>();
        Set<String> curTaskKeys = new HashSet<>();
        for (WaitDone done : waitDones) {
            Task task = processEngine.getTaskService().createTaskQuery().taskId(done.getId()).singleResult();
            curTasks.add(task);
            curTaskKeys.add(task.getTaskDefinitionKey());
        }
        //判断是否包含并行网关或者包含网关
        boolean hasParallelGateway = curTaskKeys.size()>1;

        revoke(curTasks,historicTaskInstance,hasParallelGateway);

        ProcessInfo processInfo = processInfoService.getById(historicTaskInstance.getProcessInstanceId());
        if(processInfo!=null){
            processInfo.setActStatus(WorkflowEnum.ProcessStatus.流程中.getStatus());
            String callback = processInfo.getCallback();
            if(!StringUtils.isEmpty(callback)){
                Object cb = SpringContextUtils.getBean(callback);
                if(cb!=null&&cb instanceof BaseTaskCallback){
                    ((BaseTaskCallback) cb).revoke(processInfo);
                }
            }
        }


    }
    private FlowNode getEndEvent(String proDefId){
        Process process = processEngine.getRepositoryService().getBpmnModel(proDefId).getMainProcess();
        Collection<FlowElement> flows = process.getFlowElements();
        Iterator var = flows.iterator();

        while (var.hasNext()) {
            FlowElement flowElement = (FlowElement) var.next();
            if(flowElement instanceof  EndEvent){
                return (FlowNode) flowElement;
            }
        }
        return null;
    }
    private void revoke(List<Task> curTasks,HistoricTaskInstance preTask,boolean hasParallelGateway){
        String preTaskKey = preTask.getTaskDefinitionKey();//上一步任务key
        FlowNode endEvent = getEndEvent(preTask.getProcessDefinitionId());

        FlowNode preUserTask = (FlowNode) getFlowElement(preTask.getProcessDefinitionId(),preTaskKey);
        ParallelGateway parallelGateway = null;
        String taskKeyFlag = null; //只留下一条线指向上一个节点
        if(hasParallelGateway){
//            //建立新方向
//            parallelGateway = new ParallelGateway();
//            parallelGateway.setId(UUIDUtils.uuid32());
//
//            List<SequenceFlow> gateway2PreTask = new ArrayList<>();
//            SequenceFlow sf2 = new SequenceFlow();
//            sf2.setId(UUIDUtils.uuid32());
//            sf2.setSourceFlowElement(parallelGateway);
//            sf2.setTargetFlowElement(preUserTask);
//            gateway2PreTask.add(sf2);
//            parallelGateway.setOutgoingFlows(gateway2PreTask);
            taskKeyFlag = curTasks.get(0).getTaskDefinitionKey();
        }

        Map<String,List<SequenceFlow>> oriSequenceFlowsMap = new HashMap<>();
        List<FlowNode> userTasks = new ArrayList<>();
        for (Task curTask : curTasks) {
            BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(preTask.getProcessDefinitionId());

            //删除历史流程走向记录
            processEngine.getHistoryService().deleteHistoricTaskInstance(curTask.getId());
            processEngine.getHistoryService().deleteHistoricTaskInstance(preTask.getId());
            String curTaskKey = curTask.getTaskDefinitionKey();//当前任务key
            FlowNode curUserTask = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curTaskKey);
            //记录原活动方向
            List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
            oriSequenceFlows.addAll(curUserTask.getOutgoingFlows());
            oriSequenceFlowsMap.put(curTaskKey,oriSequenceFlows);
            userTasks.add(curUserTask);
            //清理活动方向
            curUserTask.getOutgoingFlows().clear();

//            if(parallelGateway!=null){
//                List<SequenceFlow> curTask2Gateway = new ArrayList<>();
//                SequenceFlow sf1 = new SequenceFlow();
//                sf1.setId(UUIDUtils.uuid32());
//                sf1.setSourceFlowElement(curUserTask);
//                sf1.setTargetFlowElement(parallelGateway);
//                curTask2Gateway.add(sf1);
//                curUserTask.setOutgoingFlows(curTask2Gateway);
//
//            }else {
                //建立新方向
                List<SequenceFlow> curTask2PreTask = new ArrayList<>();
                SequenceFlow sf3 = new SequenceFlow();
                sf3.setId(UUIDUtils.uuid32());
                sf3.setSourceFlowElement(curUserTask);
                if(hasParallelGateway&&!curTask.getTaskDefinitionKey().equals(taskKeyFlag)){
                    sf3.setTargetFlowElement(endEvent);
                }else{
                    sf3.setTargetFlowElement(preUserTask);
                }
                curTask2PreTask.add(sf3);
                curUserTask.setOutgoingFlows(curTask2PreTask);
//            }
        }

        //完成任务
        for (Task curTask : curTasks) {
            String authenticatedUserId = Authentication.getAuthenticatedUserId();
            Authentication.setAuthenticatedUserId(BizUtil.getUserId());
            String authenticatedUserId2 = Authentication.getAuthenticatedUserId();

            processEngine.getTaskService().addComment(curTask.getId(), curTask.getProcessInstanceId(), "撤回");

            Map<String,Object> currentVariables = new HashMap();

            TaskNodeModel nodeModel = assembleUserTaskModel((UserTask) preUserTask);
            String handlerUsersExpression = nodeModel.getHandlerUsersExpression();

            String handlerName = getHandlerName(handlerUsersExpression);
            if(!StringUtils.isEmpty(handlerName)){
                currentVariables.put(handlerName,BizUtil.getUserId());
            }

            ThreadLocalContext.PreTaskThreadLocal.set(curTask);//记录工作流上一步任务

            //完成任务
            processEngine.getTaskService().complete(curTask.getId(),currentVariables);


            //待办撤回
            waitDoneService.removeById(curTask.getId());
            waitDoneService.removeById(preTask.getId());
//        WaitDone waitDone = waitDoneService.getById(preTask.getId());
//        waitDone.setDealTime(null);
//        waitDone.setDealUserId(null);
//        waitDone.setDealUserName(null);
//        waitDone.setStatus(0);
//        waitDone.setResult(null);
//        waitDone.setOpinion(null);
//        waitDoneService.updateById(waitDone);

            waitDoneUserService.deleteByWaitDoneId(curTask.getId());
            waitDoneUserService.deleteByWaitDoneId(preTask.getId());
        }


        //恢复原方向
        for (FlowNode userTask : userTasks) {
            userTask.setOutgoingFlows(oriSequenceFlowsMap.get(userTask.getId()));
        }
    }

    private String getHandlerName(String expression){
        if(isExpression(expression)){
            //设置处理人为当前审核人
            String e = expression.trim().substring(2, expression.trim().length() - 1);
            return e;
        }
        return null;
    }

    @Override
    public Result submit(WorkflowModel workflowModel) {
        String operation = workflowModel.getOperation();
        if (StringUtils.isEmpty(operation)) {
            throw new WorkflowTaskException("缺少参数:workflowModel.operation");
        }
        ProcessInfo processInfo = null;
        switch (operation) {
            case WorkflowContants.WORKFLOW_START:
                processInfo = workflowStart(workflowModel);
                break;
            case WorkflowContants.WORKFLOW_SUBMIT:
                processInfo = workflowSubmit(workflowModel);
                break;
        }

        return Result.OK(processInfo);
    }

    private ProcessInfo workflowStart(WorkflowModel workflowModel) {
        RuntimeService runtimeService = processEngine.getRuntimeService();

        String userId = BizUtil.getUserId();

        ProcessInstance instance = null;
        ProcessInfo processInfo = null;
        HistoryService historyService = processEngine.getHistoryService();
        IdentityService identityService = processEngine.getIdentityService();
        HistoricProcessInstance hpInst = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(workflowModel.getRelatedId()).singleResult();
        if (null != hpInst) {
            throw new WorkflowTaskException("已存在流程实例");
        }
        identityService.setAuthenticatedUserId(userId);//设置流程发起人信息
        String processKey = workflowModel.getProcessKey();
        if (StringUtils.isEmpty(processKey)) {
            throw new WorkflowTaskException("当前业务未绑定流程");
        }
        /**
         *删除流程记录
         */
        processInfo = processInfoService.getByRealtedId(workflowModel.getRelatedId());
        if(processInfo!=null){
            deleteProcessInfo(processInfo);
        }

        processInfo = new ProcessInfo();
        BeanUtils.copyProperties(workflowModel, processInfo);
        processInfo.setCreatorId(userId);
        processInfo.setCreateTime(new Date());
        processInfo.setCreatorName(BizUtil.getUser().getRealname());
        processInfo.setProcessBindId(workflowModel.getProcessBindId());
        processInfo.setActStatus(WorkflowEnum.ProcessStatus.流程中.getStatus());

        ThreadLocalContext.processInfoThreadLocal.set(processInfo);//用于任务创建时获取业务id

        ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
        UserTask firstTask = getFirstTask(processDefinition.getId());

        TaskNodeModel firstTaskModel = assembleUserTaskModel(firstTask);
        /**
         * 首任务处理人默认为自己
         */
        String handlerUsersExpression = firstTaskModel.getHandlerUsersExpression();
        if(!StringUtils.isEmpty(handlerUsersExpression)&&handlerUsersExpression.startsWith("${")&&handlerUsersExpression.endsWith("}")){
            handlerUsersExpression = handlerUsersExpression.substring(2,handlerUsersExpression.length()-1);
            workflowModel.getVariable().put(handlerUsersExpression,BizUtil.getUserId());
        }

        instance = runtimeService.startProcessInstanceById(processDefinition.getId(), workflowModel.getRelatedId(), workflowModel.getVariable());


        processInfo.setId(instance.getProcessInstanceId());

        if(!StringUtils.isEmpty(workflowModel.getCallback())){
            processInfo.setCallback(workflowModel.getCallback());
        }

        processInfoService.save(processInfo);

        Task nextTask = processEngine.getTaskService().createTaskQuery().processInstanceBusinessKey(workflowModel.getRelatedId()).taskCandidateOrAssigned(userId).singleResult();
        UserTask userTask = getNextTaskElement(nextTask);

        if (!StringUtils.isEmpty(workflowModel.getHandlerId())) {
            TaskNodeModel taskNodeModel = assembleUserTaskModel(userTask);
            handlerUsersExpression = taskNodeModel.getHandlerUsersExpression();
            if(!StringUtils.isEmpty(handlerUsersExpression)&&handlerUsersExpression.startsWith("${")&&handlerUsersExpression.endsWith("}")){
                handlerUsersExpression = handlerUsersExpression.substring(2,handlerUsersExpression.length()-1);
                workflowModel.getVariable().put(handlerUsersExpression,workflowModel.getHandlerId());
            }
        }else{
            TaskNodeModel taskNodeModel = assembleUserTaskModel(userTask);
            String nextTaskHandlerId = taskNodeModel.getDefaultHandlerId();
            handlerUsersExpression = taskNodeModel.getHandlerUsersExpression();
            if(!StringUtils.isEmpty(nextTaskHandlerId)&&!StringUtils.isEmpty(handlerUsersExpression)&&handlerUsersExpression.startsWith("${")&&handlerUsersExpression.endsWith("}")){
                handlerUsersExpression = handlerUsersExpression.substring(2,handlerUsersExpression.length()-1);
                workflowModel.getVariable().put(handlerUsersExpression,nextTaskHandlerId);
            }
        }

        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
        String name = outgoingFlows.get(0).getName();
        if(StringUtils.isEmpty(name)){
            name = "提交";
        }
        workflowModel.setResult(name);

        workflowSubmit(workflowModel);

        return processInfo;
    }

    /**
     * 设置流程变量
     * @param workflowModel
     */
    private void setWorkflowVariable(WorkflowModel workflowModel,Task task) {
        String lineId = workflowModel.getLineId();
        String userId = BizUtil.getUserId();
        //如果有传处理人
        Map<String, Object> taskHandler = workflowModel.getTaskHandler();

        if(!StringUtils.isEmpty(lineId)){
            SequenceFlow sequenceFlow = (SequenceFlow) getFlowElement(task.getProcessDefinitionId(), lineId);

            FlowNode targetNode = (FlowNode) sequenceFlow.getTargetFlowElement();
            List<UserTask> nextTasks = new ArrayList<>();//下一步任务节点
            if(targetNode instanceof ParallelGateway){//并行网关
                List<SequenceFlow> outgoingFlows = targetNode.getOutgoingFlows();
                for (SequenceFlow outgoingFlow : outgoingFlows) {
                    FlowNode node2 = (FlowNode) outgoingFlow.getTargetFlowElement();
                    if(node2 instanceof UserTask){
                        nextTasks.add((UserTask) node2);
                    }
                }
            }else if(targetNode instanceof UserTask){
                nextTasks.add((UserTask) targetNode);
            }
            if(!CollectionUtils.isEmpty(nextTasks)){
                for (UserTask nextTask : nextTasks) {

                    UserTask firstTask = getFirstTask(task.getProcessDefinitionId());
                    //判断是否退回首节点
                    if(nextTask.getId().equals(firstTask.getId())){
                        workflowModel.setReturnFlag(1);
                    }
                    //设置默认处理人
                    TaskNodeModel nodeModel = assembleUserTaskModel(nextTask);
                    String handlerUsersExpression = nodeModel.getHandlerUsersExpression();
                    if(isExpression(handlerUsersExpression)){

                        //设置默认处理人
                        String e = handlerUsersExpression.trim().substring(2, handlerUsersExpression.trim().length() - 1);
                        if(!StringUtils.isEmpty(nodeModel.getDefaultHandlerId())){
                            if(nextTask.hasMultiInstanceLoopCharacteristics()){
                                String[] value = nodeModel.getDefaultHandlerId().split(",");
                                workflowModel.getVariable().put(e,Arrays.asList(value));
                            }else{
                                workflowModel.getVariable().put(e,nodeModel.getDefaultHandlerId());
                            }
                        }
                        if(!CollectionUtils.isEmpty(taskHandler)){
                            Object handlerValue = taskHandler.get(nextTask.getId());
                            if(handlerValue!=null){
                                if(nextTask.hasMultiInstanceLoopCharacteristics()){
                                    String[] value = ((String) handlerValue).split(",");
                                    handlerValue = Arrays.asList(value);
                                }

                                workflowModel.getVariable().put(e,handlerValue);
                            }
                        }
                    }
                }
            }
            //设置处理结果
            String lineName = sequenceFlow.getName();
            workflowModel.setResult(lineName);
            String conditionExpressions = sequenceFlow.getConditionExpression();
            if(!StringUtils.isEmpty(conditionExpressions)){
                String s = conditionExpressions.trim();
                if( isExpression(s)&&s.indexOf("==")!=-1){
                    String expression = s.substring(2, s.length() - 1);
                    String[] split = expression.split("==");
                    workflowModel.getVariable().put(split[0],split[1]);
                }
            }


        }

    }
    /**
     * 删除流程信息
     * @param processInfo
     */
    private void deleteProcessInfo(ProcessInfo processInfo) {
        processInfoService.removeById(processInfo.getId());
        LambdaQueryWrapper<WaitDone> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WaitDone::getProcessInstanceId,processInfo.getId());
        List<WaitDone> list = waitDoneService.list(queryWrapper);
        if(!CollectionUtils.isEmpty(list)){
            for (WaitDone waitDone : list) {
                waitDoneService.deleteWaitDone(waitDone);
            }
        }
    }

    private ProcessInfo workflowSubmit(WorkflowModel workflowModel) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        TaskService taskService = processEngine.getTaskService();
        ProcessInstance instance = null;
        ProcessInfo processInfo = null;

        String userId = BizUtil.getUserId();

        List<Task> tasks = taskService.createTaskQuery().processInstanceBusinessKey(workflowModel.getRelatedId()).taskCandidateOrAssigned(userId).orderByTaskCreateTime().desc().list();
        if (CollectionUtils.isEmpty(tasks)) {
            throw new CustomRuntimeException("用户 : " + userId + " 并不是此任务的拥有者");
        }
        Task task = tasks.get(0);

        setWorkflowVariable(workflowModel,task);

        ThreadLocalContext.PreTaskThreadLocal.set(task);//记录工作流上一步任务

        //完成任务前备份
        backupTask(task);

        taskService.claim(task.getId(), BizUtil.getUserId());

        //完成任务
        taskService.complete(task.getId(), workflowModel.getVariable());
        String processInstanceId = task.getProcessInstanceId();
        processInfo = processInfoService.getById(processInstanceId);
        instance = runtimeService
                .createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (instance == null) {//流程完成
            processInfo.setEndTime(new Date());
            processInfo.setActStatus(WorkflowEnum.ProcessStatus.流程结束.getStatus());
            //删除备份
            workflowTaskService.deleteBackupByProcInstId(processInstanceId);
        }else if(workflowModel.getReturnFlag()==1){//如果是退回
            processInfo.setActStatus(WorkflowEnum.ProcessStatus.流程退回.getStatus());
        }

        if (!StringUtils.isEmpty(workflowModel.getTitle())) {
            processInfo.setTitle(workflowModel.getTitle());
        }
        if(!StringUtils.isEmpty(workflowModel.getCallback())){
            processInfo.setCallback(workflowModel.getCallback());
        }
        processInfoService.updateById(processInfo);

        WaitDone waitDone = waitDoneService.getById(task.getId());
        if (waitDone != null) {
            waitDone.setDealTime(new Date());
            waitDone.setStatus(WorkflowEnum.WaitDoneStatus.已完成.getStatus());
            waitDone.setDealUserId(BizUtil.getUserId());
            waitDone.setDealUserName(BizUtil.getUser().getRealname());
            waitDone.setOpinion(workflowModel.getOpinion());
            waitDone.setResult(workflowModel.getResult());
            waitDoneService.updateById(waitDone);
        }
        return processInfo;
    }
    private void backupTask(Task task) {
        if(!isMultiInstance(task)){
            workflowTaskService.backupTask(task.getId());
        }
    }

    /**
     * 是否会签
     * @param currentTask
     * @return
     */
    private boolean isMultiInstance(Task currentTask) {
        UserTask userTask = (UserTask) getFlowElement(currentTask.getProcessDefinitionId(), currentTask.getTaskDefinitionKey());
        return userTask!=null&&userTask.hasMultiInstanceLoopCharacteristics();
    }

    /**
     * 部署bnmp2.0流程
     *
     * @param inputStream : bmnp2.0文件的输入流
     * @return
     */
    public Result deployProcess(InputStream inputStream) {
        RepositoryService repositoryService = processEngine.getRepositoryService();

        String deploymentName = UUIDUtils.uuid32();
        DeploymentBuilder createDeployment = repositoryService.createDeployment().name(deploymentName);
        Deployment deployment = null;

        ZipInputStream zipInputStream = null;
        try {
            Charset gbk = Charset.forName("gbk");
            zipInputStream = new ZipInputStream(inputStream, gbk);
            createDeployment.addZipInputStream(zipInputStream); //关联流程定义文件

            deployment = createDeployment.deploy(); //部署流程

            ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
            ProcessDefinition lastestProcessDefinition = definitionQuery.deploymentId(deployment.getId()).singleResult();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(lastestProcessDefinition.getId());

            TaskService taskService = processEngine.getTaskService();
            List<Task> tasks = taskService.createTaskQuery().processDefinitionKey(lastestProcessDefinition.getKey()).list();
            if (tasks != null && !tasks.isEmpty()) {
                this.updateProcessDefinitionModel(tasks, bpmnModel, lastestProcessDefinition);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (zipInputStream != null)
                    zipInputStream.close();
            } catch (Exception e) {
            }
        }

        return Result.OK(deployment);
    }

    @Override
    public boolean isProcessEnd(String instanceId) {
        ProcessInstance processInstance = processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        return processInstance == null;
    }

    public void deleteProcessInstance(String instanceId) {
        this.deleteProcessInstance(instanceId, (String) null);
    }


    @Override
    public TaskApproveModel queryFlowNodeData(String taskId) {
        Task currentTask = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        if (currentTask == null) {
            throw new CustomRuntimeException("该任务不存在");
        }
        return this.listNextTaskEntity(currentTask.getProcessDefinitionId(), currentTask);
    }

    @Override
    public List<TreeNode> selectDealUser(String taskKey) {

        List<TreeNode> treeList;
        if(StringUtils.isEmpty(taskKey)){
            return sysUserService.userTreeList();
        }
        TaskNodeAttr taskNodeAttr = taskNodeAttrService.getById(taskKey);

        if (taskNodeAttr != null) {
            Set<TreeNode> nodeList = new HashSet<>();

            List<SysDepart> sysDeparts = sysDepartService.queryDepartList();
            Map<String, TreeNode> departNodeMap = new HashMap<>();
            sysDeparts.forEach(bean -> {
                TreeNode treeNode = new TreeNode();
                treeNode.setKey(bean.getId());
                treeNode.setValue(bean.getId());
                treeNode.setTitle(bean.getDepartName());
                treeNode.setParentKey(bean.getParentId());
                treeNode.setIsLeaf(false);
                departNodeMap.put(treeNode.getKey(), treeNode);
            });
            List<TaskNodeHandlerRule> handlerRuleList = taskNodeAttr.getHandlerRuleList();
            if(CollectionUtils.isEmpty(handlerRuleList)){
                for (TaskNodeHandlerRule rule : handlerRuleList) {
                    String handlerType = rule.getHandlerType();
                    String ruleHandlerValue = rule.getHandlerValue();
                    String handlerDeptId = rule.getHandlerDeptId();

                    if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.用户.getType())) {
                        String[] userIds = ruleHandlerValue.split(",");
                        List<SysUser> sysUsers = sysUserService.listByIds(Arrays.asList(userIds));
                        assembleTreeNodeData(sysUsers, nodeList);
                    } else if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门.getType())) {
                        String[] deptIds = ruleHandlerValue.split(",");
                        List<SysUserDepart> sysUserDeparts = sysUserDepartService.queryUserDepartByDepIds(Arrays.asList(deptIds));
                        for (SysUserDepart sysUserDepart : sysUserDeparts) {
                            SysUser sysUser = sysUserService.getById(sysUserDepart.getUserId());
                            if (sysUser != null) {
                                TreeNode treeNode = new TreeNode();
                                treeNode.setKey(UUIDUtils.uuid32());
                                treeNode.setValue(sysUser.getId());
                                treeNode.setTitle(sysUser.getRealname());
                                treeNode.setParentKey(sysUserDepart.getDepId());
                                treeNode.setIsLeaf(true);
                                nodeList.add(treeNode);
                            }
                        }
                    } else if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.角色.getType())) {
                        String[] roleIds = ruleHandlerValue.split(",");
                        List<SysUser> sysUsers = sysUserService.getUserByRoleIds(Arrays.asList(roleIds));
                        assembleTreeNodeData(sysUsers, nodeList);
                    } else if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.职务.getType())) {
                        String[] postCode = ruleHandlerValue.split(",");
                        List<SysUser> sysUsers = sysUserService.getUserByPostCodes(Arrays.asList(postCode));
                        assembleTreeNodeData(sysUsers, nodeList);
                    } else if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门内角色.getType())) {
                        String[] roleIds = ruleHandlerValue.split(",");
                        //如果无值，默认查当期登录部门
                        List<String> deptIds = BizUtil.getUser().getDeptIdList();
                        if(!StringUtils.isEmpty(handlerDeptId)){
                            deptIds =  Arrays.asList(handlerDeptId.split(","));
                        }
                        List<SysUser> sysUsers = sysUserService.getListByRoleIdsAndDeptIds(Arrays.asList(roleIds),deptIds );
                        assembleTreeNodeData(sysUsers, nodeList);
                    }else if (handlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门内职务.getType())) {
                        String[] postCodes = ruleHandlerValue.split(",");
                        //如果无值，默认查当期登录部门
                        List<String> deptIds = BizUtil.getUser().getDeptIdList();
                        if(!StringUtils.isEmpty(handlerDeptId)){
                            deptIds =  Arrays.asList(handlerDeptId.split(","));
                        }
                        List<SysUser> sysUsers = sysUserService.getListByPostCodesAndDeptIds(Arrays.asList(postCodes),deptIds );
                        assembleTreeNodeData(sysUsers, nodeList);
                    }
                }

                List<TreeNode> tempDepartNodes = new ArrayList<>();
                for (TreeNode treeNode : nodeList) {
                    assembleParentNodes(treeNode, departNodeMap, tempDepartNodes);
                }
                nodeList.addAll(tempDepartNodes);
                treeList = TreeNodeUtil.generalTreeList(nodeList);
            }else{
                treeList = sysUserService.userTreeList();
            }
        } else {
            treeList = sysUserService.userTreeList();
        }
        return treeList;
    }


    /**
     * 组装父节点
     *
     * @param departNodes
     */
    private void assembleParentNodes(TreeNode node, Map<String, TreeNode> departNodes, List<TreeNode> result) {
        for (Map.Entry<String, TreeNode> entry : departNodes.entrySet()) {
            if (entry.getKey().equals(node.getParentKey()) && !result.contains(entry.getValue())) {
                TreeNode parentNode = entry.getValue();
                result.add(parentNode);
                assembleParentNodes(parentNode, departNodes, result);
            }
        }
    }

    private void assembleTreeNodeData(List<SysUser> sysUsers, Set<TreeNode> result) {
        if (!CollectionUtils.isEmpty(sysUsers)) {
            for (SysUser sysUser : sysUsers) {
                List<SysUserDepart> sysUserDeparts = sysUserDepartService.queryUserDepartByUserId(sysUser.getId());
                if (!CollectionUtils.isEmpty(sysUserDeparts)) {
                    for (SysUserDepart sysUserDepart : sysUserDeparts) {
                        TreeNode treeNode = new TreeNode();
                        treeNode.setKey(UUIDUtils.uuid32());
                        treeNode.setValue(sysUser.getId());
                        treeNode.setTitle(sysUser.getRealname());
                        treeNode.setParentKey(sysUserDepart.getDepId());
                        treeNode.setIsLeaf(true);
                        result.add(treeNode);
                    }
                } else {
                    TreeNode treeNode = new TreeNode();
                    treeNode.setKey(UUIDUtils.uuid32());
                    treeNode.setValue(sysUser.getId());
                    treeNode.setTitle(sysUser.getRealname());
                    treeNode.setParentKey("");
                    treeNode.setIsLeaf(true);
                    result.add(treeNode);
                }
            }
        }
    }

    @Override
    public void showProcessImageByBizId(String bizId, OutputStream outputStream) throws IOException {
        InputStream imageStream = null;
        try {
            List<String> activities = new ArrayList();
            List<Task> taskList = processEngine.getTaskService().createTaskQuery().processInstanceBusinessKey(bizId).list();
            HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceBusinessKey(bizId).singleResult();
            if (historicProcessInstance != null) {
                ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
                BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(historicProcessInstance.getProcessDefinitionId());
                if (taskList != null && taskList.size() != 0) {
                    taskList.forEach(t->{
                        activities.add(t.getTaskDefinitionKey());
                    });
                } else {
                    activities.add(historicProcessInstance.getEndActivityId());
                }

                this.generateFlowLabel(bpmnModel);

                imageStream = pec.generateDiagram(bpmnModel, "png", activities, HIGH_LIGHTED_FLOWS, "宋体", "宋体", "黑体", (ClassLoader) null, 2.0D);
                byte[] buffer = new byte[8192];

                int bytesRead;
                while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } catch (Exception e) {
            throw new CustomRuntimeException("【异常】-获取流程图失败！" + e.toString());
        } finally {
            this.close(imageStream, outputStream);
        }
    }

    @Override
    public void showProcessImageByProcessDefineKey(String processDefineKey, OutputStream outputStream) throws IOException {
        ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(processDefineKey).latestVersion().singleResult();
        String resourceName = processDefinition.getDiagramResourceName();
        InputStream resourceAsStream = processEngine.getRepositoryService().getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        byte[] data = new byte[1024];
        int len;
        while ((len = resourceAsStream.read(data, 0, 1024)) != -1) {
            outputStream.write(data, 0, len);
        }
        resourceAsStream.close();
    }

    @Override
    public void assembleDealFlag(WorkflowEntity workflowEntity) {
        String id = BizUtil.getIdFieldValue(workflowEntity);
        Task task = processEngine.getTaskService().createTaskQuery().processInstanceBusinessKey(id).taskCandidateOrAssigned(BizUtil.getUserId()).singleResult();
        if(task==null){
            workflowEntity.setDealFlag(0);
        }else{
            workflowEntity.setDealFlag(1);
        }
        if(workflowEntity.getActStatus()<10&&workflowEntity.getActStatus()!=0&&BizUtil.getUserId().equals(workflowEntity.getCreatorId())){
            workflowEntity.setCancelFlag(1);//标记是否可以撤销流程
        }
        List<WaitDoneUser> waitDoneUser = waitDoneService.getCurUserByBizId(id);
        if(!CollectionUtils.isEmpty(waitDoneUser)){
            String waitUserName = waitDoneUser.stream().map(WaitDoneUser::getWaitUserName).collect(Collectors.joining(","));
            workflowEntity.setWaitHandler(waitUserName);
        }
    }
    @Override
    public Integer getDealFlagByBizId(String bizId) {
        Task task = processEngine.getTaskService().createTaskQuery().processInstanceBusinessKey(bizId).taskCandidateOrAssigned(BizUtil.getUserId()).singleResult();
        if(task==null){
            return 0;
        }else{
            return 1;
        }
    }

    @Override
    public List<ProcessBean> definitionList(ProcessBean processBean) {
        Integer page = processBean.getPageNo();
        Integer limit = processBean.getPageSize();
        List<ProcessBean> resultList = new ArrayList<>();
        ProcessDefinitionQuery query = createProcessDefinitionQueue(processBean);
        List<ProcessDefinition> list = page == null || limit == null ?  query.list() : query.listPage((page - 1) * limit, limit);
        List<ProcessBean> result = list.stream().map(processDefinition ->
        {
            ProcessBean pb = new ProcessBean();
            resultList.add(pb);
            pb.setSuspended(processDefinition.isSuspended());
            pb.setProcessDefinitionId(processDefinition.getId());
            pb.setProcessDefinitionKey(processDefinition.getKey());
            pb.setDeploymentId(processDefinition.getDeploymentId());
            pb.setProcessDefinitionName(processDefinition.getName());
            pb.setProcessDefinitionVersion(processDefinition.getVersion());
            pb.setProcessDefinitionDescribe(processDefinition.getDescription());
            return pb;
        }).collect(toList());
        return result;
    }

    @Override
    public IPage<ProcessBean> definitionPage(ProcessBean processBean) {
        List<ProcessBean> processBeans = definitionList(processBean);
        long count = createProcessDefinitionQueue(processBean).count();
        BasePage page = BasePage.build(processBeans, count,processBean.getPageNo());
        return page;
    }

    @Override
    public List<TaskNodeModel> taskNodeList(String processDefinitionId) {
        List<TaskNodeModel> listFlowNode = new ArrayList<>();
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
        //根据流程定义获得所有的节点
        Collection<FlowElement> flows = bpmnModel.getMainProcess().getFlowElements();
        for (FlowElement flowElement : flows){
            if (flowElement instanceof UserTask){
                TaskNodeModel flowNodeData = new TaskNodeModel(flowElement.getId(),flowElement.getName());
                listFlowNode.add(flowNodeData);
            }
        }
        return listFlowNode;
    }

    /**
     * 批量提交任务
     */
    @Override
    public void batchSubmitTask(List<String> bizId, Integer dealResult) {
        for (String id : bizId) {
            Task task = processEngine.getTaskService().createTaskQuery().processInstanceBusinessKey(id).taskCandidateOrAssigned(BizUtil.getUserId()).singleResult();
            if(task!=null){
                WorkflowModel.VariableMap variableMap = new WorkflowModel.VariableMap();

                TaskApproveModel taskApproveModel = listNextTaskEntity(task.getProcessDefinitionId(), task);
                List<TaskLineModel> taskLineList = taskApproveModel.getTaskLineList();
                if(!CollectionUtils.isEmpty(taskLineList)){
                    TaskLineModel targetTaskLine = null;
                    /**
                     * 设置处理路径变量
                     */
                    for (TaskLineModel taskLineModel : taskLineList) {
                        String conditionExpression = taskLineModel.getConditionExpression();
                        if(StringUtils.isEmpty(conditionExpression)){
                            targetTaskLine = taskLineModel;
                            break;
                        }else if(isExpression(conditionExpression)){
                            String e = conditionExpression.substring(2, conditionExpression.length() - 1);
                            String[] arr = e.split("==");
                            if(arr.length>0){
                                if(arr[1].trim().equals(dealResult.toString())){
                                    variableMap.put(arr[0],dealResult);
                                    targetTaskLine = taskLineModel;
                                    break;
                                }
                            }
                        }
                    }

                    /**
                     * 设置处理人变量
                     */
                    if(targetTaskLine!=null){
                        for (TaskNodeModel node : targetTaskLine.getTaskNodeList()) {
                            String defaultHandlerId = node.getDefaultHandlerId();
                            String handlerUsersExpression = node.getHandlerUsersExpression();
                            if(!StringUtils.isEmpty(defaultHandlerId)&&isExpression(handlerUsersExpression)){
                                String name = handlerUsersExpression.substring(2, handlerUsersExpression.length() - 1);
                                variableMap.put(name,defaultHandlerId);
                            }
                        }

                        //完成任务
                        processEngine.getTaskService().claim(task.getId(), BizUtil.getUserId());
                        processEngine.getTaskService().complete(task.getId(), variableMap);

                        ProcessInfo processInfo = processInfoService.getByRealtedId(id);
                        if(processInfo==null)continue;

                        ProcessInstance instance = processEngine.getRuntimeService()
                                .createProcessInstanceQuery().processInstanceId(processInfo.getId()).singleResult();
                        if (instance == null) {//流程完成
                            processInfo.setEndTime(new Date());
                            processInfo.setActStatus(WorkflowEnum.ProcessStatus.流程结束.getStatus());
                        }
                        processInfoService.updateById(processInfo);

                        WaitDone waitDone = waitDoneService.getById(task.getId());
                        if (waitDone != null) {
                            waitDone.setDealTime(new Date());
                            waitDone.setStatus(WorkflowEnum.WaitDoneStatus.已完成.getStatus());
                            waitDone.setDealUserId(BizUtil.getUserId());
                            waitDone.setDealUserName(BizUtil.getUser().getRealname());
                            waitDone.setResult(targetTaskLine.getLineName());
                            waitDoneService.updateById(waitDone);
                        }
                        /**
                         * 回调
                         */
                        String callback = processInfo.getCallback();
                        if(!StringUtils.isEmpty(callback)){
                            BaseTaskCallback taskCallback = (BaseTaskCallback) SpringContextUtils.getBean(callback);
                            if(taskCallback!=null){
                                taskCallback.execute(processInfo);
                            }
                        }
                    }
                }
            }

        }

    }

    /**
     *
     * @param bizId
     * @param deleteWaitDone 是否删除待办
     */
    @Override
    public void deleteProcessByBizId(String bizId,Boolean deleteWaitDone) {
        ProcessInfo processInfo = processInfoService.getByRealtedId(bizId);
        if(processInfo!=null){
            deleteProcessInstance(processInfo.getId());

            processInfo.setActStatus(WorkflowEnum.ProcessStatus.未开启.getStatus());
            String callback = processInfo.getCallback();
            if(!StringUtils.isEmpty(callback)){
                BaseTaskCallback taskCallback = (BaseTaskCallback) SpringContextUtils.getBean(callback);
                taskCallback.execute(processInfo);
            }
            waitDoneService.updateStatusByBizId(bizId,1);//更新待办表数据状态

            processInfoService.removeById(processInfo.getId());
            if(deleteWaitDone!=null&&deleteWaitDone){
                waitDoneService.deleteByBizId(bizId);
            }
        }

    }

    private boolean isExpression(String expression){
        return !StringUtils.isEmpty(expression)&&expression.startsWith("${")&&expression.endsWith("}");
    }


    protected void close(InputStream inputStream, OutputStream outputStream) {
        try {
            if (inputStream != null) {
                inputStream.close();
            }

            if (outputStream != null) {
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

    protected TaskApproveModel listNextTaskEntity(String processDefinitionId, Task task) {
        List<TaskLineModel> taskLineModels = null;
        List<TaskNodeField> taskFields = null;
        String executionId = task.getExecutionId();
        Process process = processEngine.getRepositoryService().getBpmnModel(processDefinitionId).getMainProcess();
        Collection<FlowElement> flows = process.getFlowElements();
        ExecutionEntity execution = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery().executionId(executionId).singleResult();
        String taskDefinitionKey = execution.getActivityId();
        Iterator var = flows.iterator();

        while (var.hasNext()) {
            FlowElement flowElement = (FlowElement) var.next();
            String id = flowElement.getId();
            if (taskDefinitionKey.equals(id)) {
                taskLineModels = new ArrayList();
                FlowNode currentNode = (FlowNode) process.getFlowElement(id);
                this.findNextTargetNode(process, currentNode, taskLineModels, task);
                break;
            }
        }

        TaskApproveModel taskApproveModel = new TaskApproveModel();
        taskFields= taskNodeFieldService.findByTaskKey(task.getTaskDefinitionKey());
        taskApproveModel.setTaskLineList(taskLineModels);
        taskApproveModel.setTaskFieldList(taskFields);

        UserTask firstTask = getFirstTask(task.getProcessDefinitionId());
        if(task.getTaskDefinitionKey().equals(firstTask.getId())){
            taskApproveModel.setEditFlag(1);
        }
        return taskApproveModel;
    }

    public UserTask getFirstTask(String processDefinitionId) {
        UserTask userTask = null;
        Process process = processEngine.getRepositoryService().getBpmnModel(processDefinitionId).getMainProcess();
        Collection<FlowElement> flows = process.getFlowElements();
        for (FlowElement flowElement : flows) {
            if (StartEvent.class.isAssignableFrom(flowElement.getClass())) {

                List<SequenceFlow> listSequenceFlow = ((FlowNode) flowElement).getOutgoingFlows();
                for (SequenceFlow sequenceFlow : listSequenceFlow) {
                    FlowElement element = sequenceFlow.getTargetFlowElement();
                    if (UserTask.class.isAssignableFrom(element.getClass())) {
                        userTask = (UserTask) element;
                        break;
                    }
                }
                break;
            }
        }
        return userTask;
    }
    public TaskNodeModel getFirstTaskByBizId(String bizId) {
        HistoricProcessInstance processInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceBusinessKey(bizId).singleResult();
        TaskNodeModel flowNodeData = null;
        if(processInstance!=null){
            UserTask firstTask = getFirstTask(processInstance.getProcessDefinitionId());
            flowNodeData = new TaskNodeModel(firstTask.getId(),firstTask.getName());
        }
        return flowNodeData;

    }

    /**
     * 查询下一个任务节点
     * @param process
     * @param currentNode
     * @param result
     * @param task
     */
    protected void findNextTargetNode(Process process, FlowNode currentNode, List<TaskLineModel> result, Task task) {
        List<SequenceFlow> listSequenceFlow = currentNode.getOutgoingFlows();
        Iterator var5 = listSequenceFlow.iterator();
        UserTask firstTask = getFirstTask(task.getProcessDefinitionId());

        while (var5.hasNext()) {
            SequenceFlow sequenceFlow = (SequenceFlow) var5.next();
            FlowElement element = sequenceFlow.getTargetFlowElement();
            String lineName = sequenceFlow.getName();
            String conditionExpressions = sequenceFlow.getConditionExpression();
            String id = sequenceFlow.getId();

            Class<? extends FlowElement> elementClass = element.getClass();
            //排他网关或者包含网关
            if ((element instanceof  ExclusiveGateway)||(element instanceof InclusiveGateway)) {
                this.findNextTargetNode(process, (FlowNode) process.getFlowElement(element.getId()), result, task);
            } else if(ParallelGateway.class.isAssignableFrom(elementClass)){//并行网关
                TaskLineModel taskLineModel = new TaskLineModel();
                taskLineModel.setLineName(lineName);
                taskLineModel.setLineId(id);

                taskLineModel.setConditionExpression(conditionExpressions);
                List<TaskNodeModel> taskNodeList = taskLineModel.getTaskNodeList();
                findNextTargetNodeByParallel(process,currentNode,taskNodeList,firstTask,task);
                result.add(taskLineModel);
            }else if (EndEvent.class.isAssignableFrom(elementClass)){//结束事件
                TaskLineModel taskLineModel = new TaskLineModel();
                taskLineModel.setLineId(id);
                taskLineModel.setLineName(lineName);
                taskLineModel.setConditionExpression(conditionExpressions);
                TaskNodeModel flowNodeData = new TaskNodeModel();
                flowNodeData.setIsEndEvent(1);
                flowNodeData.setTaskKey(element.getId());
                flowNodeData.setTaskName(element.getName());
                flowNodeData.setCanChooseHandler(0);

                taskLineModel.getTaskNodeList().add(flowNodeData);
                result.add(taskLineModel);

            } else if (UserTask.class.isAssignableFrom(elementClass)){//用户任务
                TaskLineModel taskLineModel = new TaskLineModel();
                taskLineModel.setLineId(id);
                taskLineModel.setLineName(lineName);
                taskLineModel.setConditionExpression(conditionExpressions);
                TaskNodeModel flowNodeData = assembleUserTaskModel((UserTask) element, firstTask, task);
                taskLineModel.getTaskNodeList().add(flowNodeData);
                result.add(taskLineModel);
            }
        }
        /**
         * 排序
         */
        Collections.sort(result, (a, b) -> {
            Integer dealResultFlag1 = getDealResultFlag(a);
            Integer dealResultFlag2 = getDealResultFlag(b);
            return dealResultFlag1-dealResultFlag2;
        });

    }
    private Integer getDealResultFlag(TaskLineModel taskLineModel){
        String conditionExpression = taskLineModel.getConditionExpression();
        Integer result = 0;
        if(conditionExpression.startsWith("${")&&conditionExpression.endsWith("}")){
            String e = conditionExpression.trim().substring(2, conditionExpression.trim().length() - 1);
            if(e.contains("==")){
                result = Integer.parseInt(e.split("==")[1]);
            }else if(e.contains(">")){
                result = Integer.parseInt(e.split(">")[1])+1;
            }else if(e.contains("<")){
                result = Integer.parseInt(e.split(">")[1])-1;
            }
        }
        return result;
    }
    /**
     * 通过并行网关获取下一步任务
     */
    protected void findNextTargetNodeByParallel(Process process, FlowNode currentNode, List<TaskNodeModel> result, UserTask firstTask,Task task) {
        List<SequenceFlow> listSequenceFlow = currentNode.getOutgoingFlows();
        Iterator var5 = listSequenceFlow.iterator();

        while (var5.hasNext()) {
            SequenceFlow sequenceFlow = (SequenceFlow) var5.next();
            FlowElement element = sequenceFlow.getTargetFlowElement();
            Class<? extends FlowElement> elementClass = element.getClass();
            //排他网关或者包含网关
            if (ExclusiveGateway.class.isAssignableFrom(elementClass)||InclusiveGateway.class.isAssignableFrom(elementClass)) {
                this.findNextTargetNodeByParallel(process, (FlowNode) process.getFlowElement(element.getId()), result, firstTask,task);
            }  else if (UserTask.class.isAssignableFrom(elementClass)){//用户任务
                TaskNodeModel model = assembleUserTaskModel((UserTask) element, firstTask,task);
                result.add(model);
            }
        }

    }

    private FlowElement getFlowElement(String processDefinitionId,String elementId){
        Process process = processEngine.getRepositoryService().getBpmnModel(processDefinitionId).getMainProcess();
        Collection<FlowElement> flows = process.getFlowElements();
        Iterator var = flows.iterator();

        while (var.hasNext()) {
            FlowElement flowElement = (FlowElement) var.next();
            String id = flowElement.getId();
            if (elementId.equals(id)) {
                return flowElement;
            }
        }

        return null;
    }

    /**
     * 根据当前任务获取下一个用户任务
     * @param task
     * @return
     */
    private UserTask getNextTaskElement(Task task){
        UserTask userTask = (UserTask) getFlowElement(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        List<UserTask> nextUserTask = getNextUserTask(userTask);

        if(!CollectionUtils.isEmpty(nextUserTask)){
            return nextUserTask.get(0);
        }

        return null;
    }

    /**
     * 获取下一个用户任务
     * @param flowNode
     * @return
     */
    private List<UserTask> getNextUserTask(FlowNode flowNode){
        List<UserTask> list = new ArrayList<>();
        assembleNextUserTask(flowNode,list);
        return list;
    }
    private void assembleNextUserTask(FlowNode flowNode,List<UserTask> userTasks){
        List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
            if(targetFlowElement instanceof Gateway){
                assembleNextUserTask((FlowNode) targetFlowElement,userTasks);
            }else if(targetFlowElement instanceof UserTask){
                userTasks.add((UserTask) targetFlowElement);
            }
        }

    }


    /**
     * 组装下一步任务model
     * @param firstTask 首任务节点
     * @param task 当前任务
     * @return
     */
    private TaskNodeModel assembleUserTaskModel(UserTask element,UserTask firstTask,Task task){

        TaskNodeModel flowNodeData = new TaskNodeModel();
        flowNodeData.setTaskKey(element.getId());
        flowNodeData.setTaskName(element.getName());
        flowNodeData.setIsMultiInstance(element.hasMultiInstanceLoopCharacteristics() ? 1 : 0);
        try {
            flowNodeData.setHandlerUsersExpression(flowNodeData.getIsMultiInstance() == 1 ? element.getLoopCharacteristics().getInputDataItem() :  element.getCandidateUsers().get(0));
        }catch (Exception e){
            flowNodeData.setHandlerUsersExpression("${assignee}");
        }
        //判断是不是退回到申请人节点
        String defaultHandlerId = null;
        String defaultHandlerName = null;
        List<WaitDone> waitDones = null;
        if(task!=null){
            waitDones = waitDoneService.findByTaskKeyAndProcInstanceId(element.getId(), task.getProcessInstanceId());
        }
        if (firstTask!=null&&element.getId().equals(firstTask.getId())) {
            if (!CollectionUtils.isEmpty(waitDones)) {
                defaultHandlerId = waitDones.get(0).getDealUserId();
                defaultHandlerName = waitDones.get(0).getDealUserName();
                flowNodeData.setCanChooseHandler(0);//不能选择处理人
            }
        } else {
            TaskNodeAttr taskNodeAttr = taskNodeAttrService.getById(element.getId());
            if (taskNodeAttr != null) {
                flowNodeData.setCanChooseHandler(taskNodeAttr.getCanChooseHandler());
                String defaultHandlerType = taskNodeAttr.getDefaultHandlerType();
                String defaultHandlerValue = taskNodeAttr.getDefaultHandlerValue();
                String defaultHandlerDepartId = taskNodeAttr.getDefaultHandlerDeptId();
                if (!StringUtils.isEmpty(defaultHandlerType)) {
                    if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.用户.getType())) {
                        SysUser sysUser = sysUserService.getById(defaultHandlerValue);
                        if (sysUser != null) {
                            defaultHandlerId = sysUser.getId();
                            defaultHandlerName = sysUser.getRealname();
                        }
                    } else if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门.getType())) {
                        List<SysUser> sysUsers = sysUserService.queryByDepIds(Arrays.asList(defaultHandlerValue), null);
                        if (!CollectionUtils.isEmpty(sysUsers)) {
                            defaultHandlerId = sysUsers.get(0).getId();
                            defaultHandlerName = sysUsers.get(0).getRealname();
                        }
                    } else if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.角色.getType())) {
                        List<SysUser> sysUsers = sysUserService.getUserByRoleId(defaultHandlerValue);
                        if (!CollectionUtils.isEmpty(sysUsers)) {
                            defaultHandlerId = sysUsers.get(0).getId();
                            defaultHandlerName = sysUsers.get(0).getRealname();
                        }
                    } else if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门内角色.getType())) {

                        //如果无值，默认查当期登录部门
                        List<String> deptIds = BizUtil.getUser().getDeptIdList();
                        if(!StringUtils.isEmpty(defaultHandlerDepartId)){
                            deptIds =  Arrays.asList(defaultHandlerDepartId);
                        }
                        List<SysUser> sysUsers = sysUserService.getListByRoleIdsAndDeptIds(Arrays.asList(defaultHandlerValue),deptIds );
                        if (!CollectionUtils.isEmpty(sysUsers)) {
                            defaultHandlerId = sysUsers.get(0).getId();
                            defaultHandlerName = sysUsers.get(0).getRealname();
                        }
                    }else if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.职务.getType())) {
                        List<SysUser> sysUsers = sysUserService.getUserByPostCodes(Arrays.asList(defaultHandlerValue));
                        if (!CollectionUtils.isEmpty(sysUsers)) {
                            defaultHandlerId = sysUsers.get(0).getId();
                            defaultHandlerName = sysUsers.get(0).getRealname();
                        }
                    } else if (defaultHandlerType.equals(WorkflowEnum.TaskNodeHandlerType.部门内职务.getType())) {
                        //如果无值，默认查当期登录部门
                        List<String> deptIds = BizUtil.getUser().getDeptIdList();
                        if(!StringUtils.isEmpty(defaultHandlerDepartId)){
                            deptIds =  Arrays.asList(defaultHandlerDepartId);
                        }
                        List<SysUser> sysUsers = sysUserService.getListByPostCodesAndDeptIds(Arrays.asList(defaultHandlerValue),deptIds );
                        if (!CollectionUtils.isEmpty(sysUsers)) {
                            defaultHandlerId = sysUsers.get(0).getId();
                            defaultHandlerName = sysUsers.get(0).getRealname();
                        }
                    }
                }
            }
        }
        if(StringUtils.isEmpty(defaultHandlerId)){
            if (!CollectionUtils.isEmpty(waitDones)) {
                defaultHandlerId = waitDones.get(0).getDealUserId();
                defaultHandlerName = waitDones.get(0).getDealUserName();
            }
        }
        flowNodeData.setDefaultHandlerId(defaultHandlerId);
        flowNodeData.setDefaultHandlerName(defaultHandlerName);

        return flowNodeData;
    }
    /**
     * 组装下一步任务model
     * @return
     */
    private TaskNodeModel assembleUserTaskModel(UserTask element){
        return assembleUserTaskModel(element,null,null);
    }

    public void deleteProcessInstance(String instanceId, String deleteReason) {
        ProcessInstance processInstance = processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        if (processInstance == null) {
            processEngine.getHistoryService().deleteHistoricProcessInstance(instanceId);
        } else {
            processEngine.getRuntimeService().deleteProcessInstance(instanceId, deleteReason);
            processEngine.getHistoryService().deleteHistoricProcessInstance(instanceId);
        }
        workflowTaskService.deleteBackupByProcInstId(instanceId);//删除备份
    }

    /**
     * 更新流程定义
     *
     * @param tasks                    流程任务
     * @param bpmnModel                流程模型
     * @param lastestProcessDefinition 最新流程模型
     */
    @Transactional
    public void updateProcessDefinitionModel(List<Task> tasks, BpmnModel bpmnModel, ProcessDefinition lastestProcessDefinition) {
        Map<String, FlowElement> elementMap = bpmnModel.getMainProcess().getFlowElementMap();
        String lastestProcessDefinitionId = lastestProcessDefinition.getId();

        String processInstanceId = null;
        String taskDefinitionId = null;
        for (Task task : tasks) {
            taskDefinitionId = task.getTaskDefinitionKey();
            processInstanceId = task.getProcessInstanceId();

            if (elementMap.get(taskDefinitionId) != null) {
                processTaskMapper.updateProcessDefinitionModel(processInstanceId, lastestProcessDefinitionId);
            }
        }
    }


    public void generateFlowLabel(BpmnModel bpmnModel) {
        Map<String, List<GraphicInfo>> flowLocations = bpmnModel.getFlowLocationMap();
        String flowKey = null;
        GraphicInfo labelGraph = null;
        Map.Entry<String, List<GraphicInfo>> flowLocationEntry = null;
        List<GraphicInfo> flowLocationPoints = null;
        Iterator iter = flowLocations.entrySet().iterator();

        while (iter.hasNext()) {
            flowLocationEntry = (Map.Entry) iter.next();
            flowKey = (String) flowLocationEntry.getKey();
            if (bpmnModel.getLabelGraphicInfo(flowKey) == null) {
                flowLocationPoints = (List) flowLocationEntry.getValue();
                labelGraph = generateLabelGraph(flowLocationPoints);
                bpmnModel.addLabelGraphicInfo(flowKey, labelGraph);
            }
        }

        this.setFlowLabelStyle();
    }

    private void setFlowLabelStyle() {
        try {
            Field labelColorField = DefaultProcessDiagramCanvas.class.getDeclaredField("LABEL_COLOR");
            boolean accessible = labelColorField.isAccessible();
            labelColorField.setAccessible(true);
            labelColorField.set((Object) null, Color.black);
            labelColorField.setAccessible(accessible);
        } catch (NoSuchFieldException var3) {
            throw new CustomRuntimeException("调整activiti流程图中流程线名称显示样式失败");
        } catch (IllegalAccessException var4) {
            throw new CustomRuntimeException("调整activiti流程图中流程线名称显示样式失败");
        }
    }

    private static GraphicInfo generateLabelGraph(List<GraphicInfo> flowLocationPoints) {
        GraphicInfo endPoint = flowLocationPoints.get(1);
        GraphicInfo startPoint = flowLocationPoints.get(0);
        GraphicInfo labelGraphicInfo = new GraphicInfo();
        double width = 30.0D;
        double height = 30.0D;
        labelGraphicInfo.setWidth(width);
        labelGraphicInfo.setHeight(height);
        double endPointX = endPoint.getX();
        double endPointY = endPoint.getY();
        double startPointX = startPoint.getX();
        double startPointY = startPoint.getY();
        labelGraphicInfo.setX((startPointX + endPointX - width) / 2.0D);
        labelGraphicInfo.setY((startPointY + endPointY - height) / 2.0D);
        return labelGraphicInfo;
    }


    protected ProcessDefinitionQuery createProcessDefinitionQueue(ProcessBean bean) {
        ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();

        query.latestVersion();

        if (org.apache.commons.lang3.StringUtils.isNotBlank(bean.getDeploymentId())) {
            query.deploymentId(bean.getDeploymentId());
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(bean.getProcessDefinitionId())) {
            query.processDefinitionId(bean.getProcessDefinitionId());
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(bean.getProcessDefinitionName())) {
            query.processDefinitionNameLike(bean.getProcessDefinitionName());
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(bean.getProcessDefinitionKey())) {
            query.processDefinitionKeyLike(bean.getProcessDefinitionKey());
        }

        if (bean.getProcessDefinitionVersion() != null) {
            query.processDefinitionVersion(bean.getProcessDefinitionVersion());
        }

        return query;
    }
}
